So I created a snake game with a border created with 2d sprites. I have my game window set to 16:9, when in this resolution the images look fine. However, scaling to anything else begins to make the game look weird. I want the game window to be re-sizable. How can I make my sprites stretch and shrink based on the current resolution?
I have already tried creating a sprite that is 120 in Width and 1 in Height, then using the x,y,z scales to change the scale to 16. This produced a huge sprite.
I am experimenting with using a canvas scaler, but with no success.
My end goal isn't to have my game fit pre-defined resolutions like 16:9, but to scale according to the current window size. So that if they make the window extremely thin, the game will only make the top and bottom borders extremely thin, while still confing the game play into the borders.
Below I post the screenshots of how my sprites are setup. And how they are placed into the hierarchy.
Border sprite - this sprite's width is now 70 pixels, because this is how it was given to me.
Border in hierarchy, position, scale, and rotation are defaults. Then for example the BorderTop is moved 25 on the y axis to move it to the top of the screen.
Camera setup
Example resolutions and current output
16:9
5:4
Add a simple script to every border:
public class Border : MonoBehaviour {
enum BorderTypes
{
bottom, top, left, right
}
[SerializeField] float borderOffset = 0.1f;
[SerializeField] BorderTypes type = BorderTypes.top;
// Use this for initialization
void Start () {
switch (type)
{
case BorderTypes.bottom:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, borderOffset, 10));
break;
case BorderTypes.top:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(0.5f, 1 - borderOffset, 10));
break;
case BorderTypes.left:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(borderOffset, 0.5f, 10));
break;
case BorderTypes.right:
transform.position = Camera.main.ViewportToWorldPoint(new Vector3(1 - borderOffset, 0.5f, 10));
break;
default:
break;
}
}
}
You can use a simple way:
First, create a Canvas
in Canvas component in Inspector, set Render Mode to Screen Space - Camera and drag your main camera to Render Camera field.
Then, in Canvas Scaler component in Inspector window, set UI Scale Mode to Scale Width Screen Size and other settings like this image
Now drag your game objects to Canvas.
First, you should not change your sprites. You problem is a game viewport. You simply cannot have 16:9 fixed aspect ratio on every device in "full-screen". You have 2 options here:
Don't care about aspect ratio and adapt your gameplay, make your canvas scalermode to "scale with screen size" and reference resolution something like 1920x1080 or 1600:900 or 800:450. Your game logic must take into account that you may have different size of screens. You can experiment in editor by switching different aspect ratios in game view.
Maintain 16:9 and therefore calculate for where to add "bars" (sides or top and down), when the game is initialized.
Related
I have an imageviewer with a couple images, When i zoom in the first image and wanna see the right side of the image. The folowing image is overlapping the inzooming image. This is very annoying. Is there a way how i can set the zoom in image on the front.
How can i set the zoomed image always on front.
See picture https://i.stack.imgur.com/5f5JZ.jpg
My imageviewer is in a container
Image red ;
red = EncodedImage.create("/HW_Delfzijl_Waddenzee_Oost.jpg");
Image blue = Image.createImage(500, 500, 0xff0000ff);
Image red2 = Image.createImage(500, 500, 0xffff0000);
Image List1[]= new Image [3];
List1[0] = red;
List1[1] = blue;
List1[2] = red2;
iv = new ImageViewer();
iv.setWidth(500);
iv.setHeight(500);
iv.setImageList(new DefaultListModel<>(List1));
Container1 = BoxLayout.encloseY( Kaarten.AuvHW, AdvSpr,iv,
Up,progressbar);
I was able to reproduce this with the following code:
Form hi = new Form("ImageViewer", BoxLayout.y());
Image red = Image.createImage(2000, 800, 0xffff0000);
Image blue = Image.createImage(2000, 500, 0xff0000ff);
ImageViewer viewer = new ImageViewer();
viewer.setImageList(new DefaultListModel<>(red, blue));
hi.add(BoxLayout.encloseY(viewer, new Label("Dummy")));
hi.show();
The problem only happens if I stand on the blue image (the second one) scale it up and then try to move. It doesn't happen when moving from the red image to the blue.
I believe this is due to this method in the ImagaViewer code. Since background isn't painted the old image isn't cleaned up. We need to add a condition that disables that while dragging. I think changing the code in that method to this will fix the problem but it's a bit risky and might trigger flickering:
protected void paintBackground(Graphics g) {
// disable background painting for performance when zooming
if(imageDrawWidth < getWidth() || imageDrawHeight < getHeight() || panPositionX != 0) {
super.paintBackground(g);
}
}
I would suggest filing an issue so we can consider the options here as this isn't trivial. One partial workaround is to use:
viewer.setImageInitialPosition(ImageViewer.IMAGE_FILL);
Which minimizes the impact of the issue.
I created a 10 000 x 10 000 pixel canvas, placed it inside a scroll pane with dimensions 300 x 300. This was implemented fine. The whole grid was drawn and I could scroll through it.
I'm tasked to instead create the same functionality, except with a 300 x 300 canvas instead. As speed is important in this program, I'm told this would work much faster.
My problem is that when I do this, I lose access to the scroll bars on the bottom and right of the scroll pane. How do I regain access to those scroll bars, to physically scroll?
The canvas is updating at 60 steps per second. What's being drawn is a square grid from the information in a 2D array.
Since the the viewport handling will be done by the drawing logic, it's rather easy to create a "ScrollPane" yourself using a GridPane:
public static ScrollBar createScrollBar(Orientation orientation, double fullSize, double canvasSize) {
ScrollBar sb = new ScrollBar();
sb.setOrientation(orientation);
sb.setMax(fullSize - canvasSize);
sb.setVisibleAmount(canvasSize);
return sb;
}
Canvas canvas = new Canvas();
canvas.setHeight(300);
canvas.setWidth(300);
ScrollBar vScroll = createScrollBar(Orientation.VERTICAL, 10000, 300);
ScrollBar hScroll = createScrollBar(Orientation.HORIZONTAL, 10000, 300);
GridPane scrollPane = new GridPane();
scrollPane.addColumn(0, canvas, hScroll);
scrollPane.add(vScroll, 1, 0);
I am trying to render 3D bar chart in SCNView using ScreenKit framework.
My rendering code is,
int height=10,y=0,x=0;
for (int i=0; i<10; i++) {
SCNBox *box1 = [SCNBox boxWithWidth:4 height:height length:2 chamferRadius:0];
boxNode1 = [SCNNode nodeWithGeometry:box1];
boxNode1.position = SCNVector3Make(x, y, 0);
SCNMaterial *material = [SCNMaterial material];
material.diffuse.contents = (NSColor *)[self.colorArray objectAtIndex:i%6];
material.specular.contents = [NSColor whiteColor];
material.shininess = 1.0;
box1.materials = #[material];
//boxNode1.transform = rot;
[scene.rootNode addChildNode:boxNode1];
x+=6;
height+=10;
y += 5 ;
}
I can render but while re-sizing the view the chart bars goes to the center of the view.
I need to render the chart, which cover the margins of the view and when Re-size it have to change accordingly. The image(s) below shows my problem.
Original Image:
Image where less stretching of both windows:
Can anyone please help me to fix the issue.
The the windows in the image that you had linked to in your original question was very stretched and that made it very hard to see what was going on. When I took that image and made the windows less stretched it was easier to have some idea of what is going on.
I think that you are seeing a general resizing issue. Either you are using springs and struts and have configured flexible margins on the left and right or you are using auto layout with a centered view with fixed width.
I assume that the red boxes that I have drawn in the image below is the bounds of your scene view in both these cases. You can easily see if this is the case by giving the scene view a different background color and resize it again.
My solution to your problem would be to change how your view resizes as the window resizes, to better meet your expectations.
In Three.js, is it possible to draw directly to the WebGL area (for a heads-up display or UI elements, for example) the way you could with a regular HTML5 canvas element?
If so, how can you get the context and what drawing commands are available?
If not, is there another way to accomplish this, through other Three.js or WebGL-specific drawing commands that would cooperate with Three.js?
My backup plan is to use HTML divs as overlays, but I think there should be a better solution.
Thanks!
You can't draw directly to the WebGL canvas in the same way you do with with regular canvas. However, there are other methods, e.g.
Draw to a hidden 2D canvas as usual and transfer that to WebGL by using it as a texture to a quad
Draw images using texture mapped quads (e.g. frames of your health box)
Draw paths (and shapes) by putting their vertices to a VBO and draw that with the appropriate polygon type
Draw text by using a bitmap font (basically textured quads) or real geometry (three.js has examples and helpers for this)
Using these usually means setting up a an orthographic camera.
However, all this is quite a bit of work and e.g. drawing text with real geometry can be expensive. If you can make do with HTML divs with CSS styling, you should use them as it's very quick to set up. Also, drawing over the WebGL canvas, perhaps using transparency, should be a strong hint to the browser to GPU accelerate its div drawing if it doesn't already accelerate everything.
Also remember that you can achieve quite much with CSS3, e.g. rounded corners, alpha transparency, even 3d perspective transformations as demonstrated by Anton's link in the question's comment.
I had exactly the same issue. I was trying to create a HUD (Head-up display) without DOM and I ended up creating this solution:
I created a separate scene with orthographic camera.
I created a canvas element and used 2D drawing primitives to render my graphics.
Then I created an plane fitting the whole screen and used 2D canvas element as a texture.
I rendered that secondary scene on top of the original scene
That's how the HUD code looks like:
// We will use 2D canvas element to render our HUD.
var hudCanvas = document.createElement('canvas');
// Again, set dimensions to fit the screen.
hudCanvas.width = width;
hudCanvas.height = height;
// Get 2D context and draw something supercool.
var hudBitmap = hudCanvas.getContext('2d');
hudBitmap.font = "Normal 40px Arial";
hudBitmap.textAlign = 'center';
hudBitmap.fillStyle = "rgba(245,245,245,0.75)";
hudBitmap.fillText('Initializing...', width / 2, height / 2);
// Create the camera and set the viewport to match the screen dimensions.
var cameraHUD = new THREE.OrthographicCamera(-width/2, width/2, height/2, -height/2, 0, 30 );
// Create also a custom scene for HUD.
sceneHUD = new THREE.Scene();
// Create texture from rendered graphics.
var hudTexture = new THREE.Texture(hudCanvas)
hudTexture.needsUpdate = true;
// Create HUD material.
var material = new THREE.MeshBasicMaterial( {map: hudTexture} );
material.transparent = true;
// Create plane to render the HUD. This plane fill the whole screen.
var planeGeometry = new THREE.PlaneGeometry( width, height );
var plane = new THREE.Mesh( planeGeometry, material );
sceneHUD.add( plane );
And that's what I added to my render loop:
// Render HUD on top of the scene.
renderer.render(sceneHUD, cameraHUD);
You can play with the full source code here:
http://codepen.io/jaamo/pen/MaOGZV
And read more about the implementation on my blog:
http://www.evermade.fi/pure-three-js-hud/
i am trying to rotate a 89x89 image inside the QLabel Widge.
#include "header.h"
disc::disc(QWidget *Parent) : QWidget(Parent)
{
orig_pixmap = new QPixmap();
rotate = new QLabel(this);
showDegrees = new QLabel(this);
orig_pixmap->load("pic.png");
degrees = 0;
rotate->resize(89,89);
rotate->move(100,10);
rotate->setStyleSheet("QLabel{background-color:red;}");
showDegrees->resize(100,100);
showDegrees->move(400,0);
}
void disc::rotate_disc()
{
QString string;
degrees++;
if(degrees == 360) degrees = 0;
QTransform rotate_disc;
rotate_disc.translate( (orig_pixmap->width()-rotate->width())/2 , (orig_pixmap->width()-rotate->height())/2);
rotate_disc.rotate(degrees,Qt::ZAxis);
QPixmap pixmap;
//pixmap = orig_disc->scaled(89,89,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
pixmap = orig_pixmap->transformed(rotate_disc,Qt::SmoothTransformation);
rotate->setPixmap(pixmap);
string.append("Degrees: " + QString::number(degrees) + "*");
showDegrees->setText(string);
}
Even though it rotates. The image's half gets rolled outside the QLabel and hence that side is not visible.How can i make it center rotate at origin(0,0) of the image center.
Here is the file
http://www65.zippyshare.com/v/85775455/file.html
if you look at it you can see that image is like bouncing to the left.how can i make it rotate inside the black area.
i setup a signal timeout at every 10ms to the rotate_disc() function. I am using this to learn Qt indepth.
Thank You!
I've done it like this...
//Move windows's coordinate system to center.
QTransform transform_centerOfWindow( 1, 0, 0, 1, width()/2, height()/2 );
//Rotate coordinate system.
transform_centerOfWindow.rotate( m_LoadingDisk_degrees );
//Draw image with offset to center of image.
QPainter painter( this );
//Transform coordinate system.
painter.setTransform( transform_centerOfWindow );
//Load image.
//Notice: As coordinate system is set at center of window, we have to center the image also... so the minus offset to come to center of image.
painter.drawPixmap( -loadingDisk.width()/2, -loadingDisk.height()/2, loadingDisk );
I think all you're really missing is the initial translation to do the rotation around the centre of the pixmap.
Move it to the origin, rotate, then move it back. And remember, transformations are applied in reverse order from how you'd expect, given how you specify them in the code.
QTransform rotate_disc;
rotate_disc.translate(orig_pixmap->width()/2.0 , orig_pixmap->height()/2.0);
rotate_disc.rotate(degrees);
rotate_disc.translate(-orig_pixmap->width()/2.0 , -orig_pixmap->height()/2.0);
If you are making a loading indicator, animated gif would be much easier. See GIF animation in Qt