Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by CaptainFrech

I am tinkering around with Map Rotation - I would love to rotate the screen (camera)

any tips how i can do this?

1 decade ago by paulh

http://impactjs.com/forums/help/drawing-an-arbitrary-part-of-the-map-double-buffering

hope this helps

1 decade ago by KirbySaysHi

I've been trying to make this happen as well for a pet project of mine. Unfortunately, Impact requires some tricks for a few reasons:

1) Impact doesn't have rendering hooks that would allow you to do things before and after rendering takes place (such as allow a component to rotate the context and restore things)

2) Impact's concept of a camera is hard-coded into the system, meaning entities and maps rely on ig.game.screen being a simple x/y. If you want to enhance the camera capabilities, you'd need to edit most of Impact's core drawing, tiling, and culling methods.

But I've got this working! :) Check out https://gist.github.com/kirbysayshi/6102134 for a fully working example.

I'll post the code here just so it's easier to view, but the canonical version should be the gist (easier to edit and track changes). Eventually I may up this to a full repo, but for now the gist suffices. I'll likely write a longer blog post describing how this works (diagrams! all this context manipulation is tricky) but for now...

The basic idea is:

Subclass your main game from RotatableGame instead of ig.Game.

Before rendering everything, resize Impact's understanding of the canvas and drawing canvas to be larger; large enough so that if the camera were to be rotated at any angle, it could still be contained by the new dimensions. The important part here is that the actual canvas element and drawing context are kept exactly the same.

The logical (not physical) is so that Impact's default draw techniques can be used, like map tiling, chunking, and entities only drawing if they're visible.

Then reposition and rotate the drawing context so that when Impact draws, everything is drawn at an angle.

When everything has been drawn, undo the rotation and translation, and reset Impact's screen and context sizes so that things like ig.game.screen += 1 still work.

Code below (remember, the gist is a better resource).

ig.module(
	'plugins.rotatablegame'
)
.requires(
	'impact.game'
)
.defines(function(){

ig.RotatableGame = ig.Game.extend({

	screenRotation: {
		centerOffset: { x: 0, y: 0 },
		angle: 0
	},

	draw: function() {

		// figure out which side of the canvas is the largest
		var maxDimension = Math.max(ig.system.width, ig.system.height);
		// and then find the hypotenuse, as it is impossible for the context,
		// at any angle, to be larger than this length
		var diagonalLen = maxDimension * Math.SQRT2;

		// save the original:
		// system.{width/height} width/height of the logical drawing surface
		// system.real{Width/Height}: width/height of the actual drawing surface in pixels
		// screen.{x/y}: upper left position of the "camera"
		var systemWidth = ig.system.width;
		var systemHeight = ig.system.height;
		var systemRealWidth = ig.system.realWidth;
		var systemRealHeight = ig.system.realHeight;
		var screenX = ig.game.screen.x;
		var screenY = ig.game.screen.y;

		// temporarily tell impact to use screen and system that are big
		// enough to cover any rotations of the original size
		ig.system.width = diagonalLen;
		ig.system.height = diagonalLen;
		ig.system.realWidth = ig.system.scale * diagonalLen;
		ig.system.realHeight = ig.system.scale * diagonalLen;

		// using the original values...
		var halfRealWidth = systemRealWidth / 2;
		var halfRealHeight = systemRealHeight / 2;
		// these are the offsets required to move the context to compensate for
		// increasing the drawing area (difference between the original real
		// context size and increased context size, divided by 2)
		var diffHalfRealWidth = ig.system.realWidth/2 - halfRealWidth;
		var diffHalfRealHeight = ig.system.realHeight/2 - halfRealHeight;

		var rotationOffsetX = halfRealWidth + this.screenRotation.centerOffset.x;
		var rotationOffsetY = halfRealHeight + this.screenRotation.centerOffset.y;

		// rotate the context itself using original center as point of rotation
		ig.system.context.translate( rotationOffsetX, rotationOffsetY );
		ig.system.context.rotate(this.screenRotation.angle);
		ig.system.context.translate( -rotationOffsetX, -rotationOffsetY );

		// translate the context to ensure that drawing that occurs outside
		// is actually captured
		ig.system.context.translate( -diffHalfRealWidth, -diffHalfRealHeight );

		// move the screen to compensate for drawing at a translated offset
		// this is not "undone" because the screen is just reset to the old
		// position at the end of the step
		ig.game.screen.x -= diffHalfRealWidth / ig.system.scale;
		ig.game.screen.y -= diffHalfRealHeight / ig.system.scale;

		// do all the typical impact stuff, draw maps, entities, etc.
		this.parent();

		// put the context back in alignment with the natural system size
		ig.system.context.translate( diffHalfRealWidth, diffHalfRealHeight );

		// undo the rotation from earlier
		ig.system.context.translate( rotationOffsetX, rotationOffsetY );
		ig.system.context.rotate(-this.screenRotation.angle);
		ig.system.context.translate( -rotationOffsetX, -rotationOffsetY );

		// undo all the width/height/screen changes
		ig.system.width = systemWidth;
		ig.system.height = systemHeight;
		ig.system.realWidth = systemRealWidth;
		ig.system.realHeight = systemRealHeight;
		ig.game.screen.x = screenX;
		ig.game.screen.y = screenY;
	}

});

});

1 decade ago by CaptainFrech

great work! thank you very much!! great example
Page 1 of 1
« first « previous next › last »